import java.io.*;
import java.util.*;


public class ACETokSentDocument {

  ACETokSentence[] m_sents;

  public ACETokSentDocument(ACEDocument doc)
  {
    readCOL(doc);
    readCFG(doc);
  }

  public void readCOL(ACEDocument doc)
  {
    int nOffset = 0;
    try {
      Vector vecSent = new Vector();
      Vector vecSOffset = new Vector();
      Vector vecSTIndex = new Vector();

      String strFile = doc.m_strDir + "/" + doc.m_strId + ".col";
      BufferedReader br = new BufferedReader(new FileReader(strFile));
      String strLine = br.readLine();
      while (strLine != null) {
	// read sentence tokens, POS tags
        StringTokenizer st = new StringTokenizer(strLine);
	st.nextToken(); // ignore word count
	Vector vecTokens = new Vector();
	Vector vecPOS = new Vector();
        while (st.hasMoreTokens()) {
	  vecTokens.add(recoverToken(st.nextToken()));
	  vecPOS.add(st.nextToken());
        }

	if (vecTokens.size() > 0) {
	  vecSOffset.add(new Integer(nOffset));
	  // synchronize tokens with raw text
	  int[] vecIndex = new int[vecTokens.size()];
	  for (int i = 0; i < vecIndex.length; i++) {
	    String strTok = (String) vecTokens.get(i);
	    if (strTok.equals("''")) {
	      int uh = nOffset;
	      while (uh < doc.m_strText.length()) {
		char c = doc.m_strText.charAt(uh);
		if (c == '"') {
		  vecIndex[i] = uh;
		  nOffset = uh + 1;
		  break;
		}
		else if (c == '\'') {
		  vecIndex[i] = uh;
		  uh++;
		  if (uh < doc.m_strText.length() && doc.m_strText.charAt(uh) == '\'')
		    nOffset = uh + 1;
		  else
		    nOffset = uh;
		  break;
		}
		else if (c == '`') {
		  vecIndex[i] = uh;
		  uh++;
		  if (uh < doc.m_strText.length() && doc.m_strText.charAt(uh) == '`')
		    nOffset = uh + 1;
		  else
		    nOffset = uh;
		  break;
		}
		else
		  uh++;
	      }
	    }
	    else {
	      int nPos = doc.m_strText.indexOf(strTok, nOffset);
	      assert doc.m_strText.substring(nOffset, nPos).trim().length() == 0 : strTok;
	      vecIndex[i] = nPos;
	      nOffset = nPos + strTok.length();
	    }
	  }
	  vecSTIndex.add(vecIndex);
	  
	  // create ACE tokenized sentence
	  ACETokSentence aceTS = new ACETokSentence(vecSent.size(), 
						    vecTokens, vecPOS);
	  vecSent.add(aceTS);
	}

        strLine = br.readLine();
      }
      br.close();

      m_sents = (ACETokSentence[]) vecSent.toArray(new ACETokSentence[0]);

      // assign entity mentions to sentences
      for (int e = 0; e < doc.m_vecEntities.size(); e++) {
	ACEEntity aceE = (ACEEntity) doc.m_vecEntities.get(e);
	ListIterator it = aceE.m_lstMentions.listIterator();
	while (it.hasNext()) {
	  ACEEMention aceEM = (ACEEMention) it.next();

	  int i = 1;
	  while (i < m_sents.length) {
	    int nEnd = ((Integer) vecSOffset.get(i)).intValue();
	    if (aceEM.m_nBeg < nEnd) {
	      if (aceEM.m_nBeg + aceEM.m_nLen > nEnd)
		System.out.println(doc.m_strText.substring(aceEM.m_nBeg,
							   aceEM.m_nBeg +
							   aceEM.m_nLen));
	      assert aceEM.m_nBeg + aceEM.m_nLen <= nEnd;
	      aceEM.setAttribute("sent", String.valueOf(i - 1));
	      m_sents[i - 1].addEMention(aceEM);
	      break;
	    }
	    i++;
	  }
	  if (i == m_sents.length) {
	    aceEM.setAttribute("sent", String.valueOf(i - 1));
	    m_sents[i - 1].addEMention(aceEM);
	  }
	  synchronizeEM(aceEM, (int[]) vecSTIndex.get(i - 1));
	}
      }

      // assign relation mentions to sentences
      for (int r = 0; r < doc.m_vecRelations.size(); r++) {
	ACERelation aceR = (ACERelation) doc.m_vecRelations.get(r);
	ListIterator it = aceR.m_lstMentions.listIterator();
	while (it.hasNext()) {
	  ACERMention aceRM = (ACERMention) it.next();
	  //	  if (aceRM.m_relation.m_bExplicit) {
	    int nSent1 = Integer.parseInt(aceRM.m_arg1.getAttribute("sent"));
	    int nSent2 = Integer.parseInt(aceRM.m_arg2.getAttribute("sent"));
	    if (nSent1 == nSent2)
	      m_sents[nSent1].addRMention(aceRM);
	    //	  }
	}
      }
    }
    catch (IOException e) {
      e.printStackTrace();
    }
  }


  public void readCFG(ACEDocument doc)
  {
    int nSent = 0;
    try {
      String strFile = doc.m_strDir + "/" + doc.m_strId + ".cfg";
      BufferedReader br = new BufferedReader(new FileReader(strFile));
      for (int i = 0; i < m_sents.length; i++) {
	String strLine = br.readLine();
	while (!strLine.startsWith("("))
	  strLine = br.readLine();
	m_sents[i].readDependencies(strLine);
      }
      br.close();
    }
    catch (IOException e) {
      e.printStackTrace();
    }
  }


  protected void synchronizeEM(ACEEMention aceEM, int[] vecIndex)
  {
    int[] beg_len = synchronize(aceEM.m_nBeg, aceEM.m_nLen, vecIndex);
    aceEM.m_nBeg = beg_len[0];
    aceEM.m_nLen = beg_len[1];

    beg_len = synchronize(aceEM.m_nHBeg, aceEM.m_nHLen, vecIndex);
    aceEM.m_nHBeg = beg_len[0];
    aceEM.m_nHLen = beg_len[1];
  }

  
  protected int[] synchronize(int nBeg, int nLen, int[] vecIndex)
  {
    int[] beg_len = new int[2];

    boolean bFound = false;
    int i = 0;
    while (i < vecIndex.length) {
      if (vecIndex[i] != -1 && nBeg <= vecIndex[i]) {
	int j = i + 1;
	while (j < vecIndex.length) {
	  if (vecIndex[i] != -1 && nBeg + nLen <= vecIndex[j])
	    break;
	  j++;
	}
	beg_len[0] = i;
	beg_len[1] = j - i;
	bFound = true;
	break;
      }
      i++;
    }
    assert bFound;

    return beg_len;
  }


  public boolean functorIsHead(String strCategory, int nArg)
  {
    return true;
  }


  public String recoverToken(String strToken)
  {
    String strResult = "";

    int nBeg = 0;
    int nPos = strToken.indexOf("-*-", nBeg);
    while (nPos != -1) {
      strResult += strToken.substring(nBeg, nPos) + "_";
      nBeg = nPos + 3;
      nPos = strToken.indexOf("-*-", nBeg);
    }
    strResult += strToken.substring(nBeg);

    return strResult;
  }


  public void displayRM()
  {
    for (int i = 0; i < m_sents.length; i++)
      m_sents[i].displayRM();
  }


  public void displayDeps()
  {
    for (int i = 0; i < m_sents.length; i++) {
      m_sents[i].displayDeps();
      System.out.println();
    }
  }


  static public void main(String[] args) 
  {
    if (args.length != 2) {
      System.out.println("Usage: java ACETokSentDocument <corpus-dir> " +
                         "<corpus-list>!");
      System.exit(1);
    }

    try {
      BufferedReader br = new BufferedReader(new FileReader(args[1]));
      String strLine = br.readLine();
      while (strLine != null) {
        strLine = strLine.trim();
        if (strLine.length() > 0) {
          // load input document
          String strInFile = args[0] + "/" + strLine;

          System.out.println("processing [" + strInFile + "] ... ");

	  ACEDocument aceDoc = new ACEDocument();
	  aceDoc.load(strInFile);

	  ACETokSentDocument aceTSDoc = new ACETokSentDocument(aceDoc);
	  aceTSDoc.displayDeps();
	  System.out.println();
	  System.out.println("-------------------------------------------");
	  System.out.println();
        }
        strLine = br.readLine();
      }
    }
    catch (IOException e) {
      System.err.println(e);
      System.exit(1);
    }
  }


  static public void main_pos(String[] args)
  {
    if (args.length != 2) {
      System.out.println("Usage: java ACETokSentDocument <corpus-dir> " +
                         "<corpus-list>!");
      System.exit(1);
    }

    TreeSet setPOS = new TreeSet();
    try {
      BufferedReader br = new BufferedReader(new FileReader(args[1]));
      String strLine = br.readLine();
      while (strLine != null) {
        strLine = strLine.trim();
        if (strLine.length() > 0) {
          // load input document
          String strInFile = args[0] + "/" + strLine;

          System.out.println("processing [" + strInFile + "] ... ");

	  ACEDocument aceDoc = new ACEDocument();
	  aceDoc.load(strInFile);

	  ACETokSentDocument aceTSDoc = new ACETokSentDocument(aceDoc);
	  for (int i = 0; i < aceTSDoc.m_sents.length; i++) {
	    for (int j = 0; j < aceTSDoc.m_sents[i].m_vecPOS.length; j++)
	      setPOS.add(aceTSDoc.m_sents[i].m_vecPOS[j]);
	  }
        }
        strLine = br.readLine();
      }
    }
    catch (IOException e) {
      System.err.println(e);
      System.exit(1);
    }

    Iterator it = setPOS.iterator();
    while (it.hasNext())
      System.out.print(it.next() + " ");
  }



}
